<template>
  <section class="v-form-maker">
    <section v-for="(fields, index) in map" :key="index" class="row">
      <section v-for="field in fields" :id="field.id" :key="field.key" class="span" :class="{'hide': hideList.includes(field.id)}">
        <v-field ref="field" :type="field.type" :option="field.option" />
      </section>
    </section>
  </section>
</template>
<script>
import VField from './../field'
import FieldMap from './../../fields/map'
import Queue from '@/utils/queue'
import { randomString } from '@/utils'
export default {
  name: 'VFormMaker',
  componentname: 'VFormMaker',
  components: { VField },
  props: {
    inner: {
      type: Object,
      default: {}
    }
  },
  data() {
    return {
      values: {},
      keyMap: {},
      map: [],
      queue: null,
      hideList: []
    }
  },
  computed: {
    components() {
      return this.inner.components
    },
    relation() {
      return this.inner.relation
    },
    _components() {
      const _map = []; const valuesIdMap = {}
      this.components.forEach(components => {
        components.forEach(com => {
          if (this.values[com.name] !== undefined) {
            valuesIdMap[com.id] = this.values[com.name]
          }
        })
      })
      this.components.forEach(components => {
        const t = []
        components.forEach(component => {
          const field = FieldMap.getField(component.type)
          const { target } = field
          t.push({
            type: target,
            id: component.id,
            option: component,
            values: this.values,
            valuesIdMap,
            key: randomString(8)
          })
        })
        _map.push(t)
      })
      return _map
    }
  },
  created() {
    this.init()
  },
  methods: {
    init() {
      this.queue = new Queue()
      this.map = this._components
      this.on_event('filed-value-change', (e) => {
        e.stopPropagation()
      })
      this.on_event('change', (e) => {
        e.stopPropagation()
        this.change()
      })
    },

    change() {
      this.queue.add(() => {
        const { relation } = this
        return Object.keys(relation).reduce((a, targetId) => {
          return a.then(() => {
            const relates = (relation[targetId] || [])
            if (relates.length > 0) {
              let result = false; let type = 1
              return relates.reduce((_a, a) => {
                return _a.then(() => {
                  const { id, operate, value, valueType, display } = a.relate
                  const target = this.getFieldById(id)
                  if (target) {
                    return Promise.resolve().then(() => {
                      const type = target.option.type
                      return Promise.resolve().then(() => target.getValue()).then(value => {
                        return {
                          lvalue: value,
                          lvalueType: FieldMap.getField(type).valueType
                        }
                      })
                    }).then(({ lvalue, lvalueType }) => {
                      return FieldMap.invokeOperate({
                        operate,
                        lvalue,
                        lvalueType,
                        rvalue: value,
                        rvalueType: valueType
                      })
                    }).then(r => {
                      result = r
                      type = display
                    })
                  }
                })
              }, Promise.resolve()).then(() => {
                console.log(result, type)
                if (result) {
                  if (type == 1) {
                    this.commit('unhide-some', targetId)
                  } else if (type == 2) {
                    this.commit('hide-some', targetId)
                  } else if (type == 3) {
                    this.commit('set-field-prop', { target: targetId, prop: 'disabled', value: true })
                  } else if (type == 4) {
                    this.commit('set-field-prop', { target: targetId, prop: 'required', value: true })
                  } else if (type == 5) {
                    this.commit('set-field-prop', { target: targetId, prop: 'required', value: false })
                  } else if (type == 6) {
                    this.commit('set-field-prop', { target: targetId, prop: 'disabled', value: false })
                  }
                } else {
                  if (type == 1) {
                    this.commit('hide-some', targetId)
                  } else if (type == 2) {
                    this.commit('unhide-some', targetId)
                  } else if (type == 3) {
                    this.commit('set-field-prop', { target: targetId, prop: 'disabled', value: false })
                  } else if (type == 4) {
                    this.commit('set-field-prop', { target: targetId, prop: 'required', value: false })
                  } else if (type == 5) {
                    this.commit('set-field-prop', { target: targetId, prop: 'required', value: true })
                  } else if (type == 6) {
                    this.commit('set-field-prop', { target: targetId, prop: 'disabled', value: true })
                  }
                }
              })
            }
          })
        }, Promise.resolve())
      })
    },

    commit(type, data) {
      switch (type) {
        case 'hide-some':
          this.hideSome(data)
          break
        case 'unhide-some':
          this.unhideSome(data)
          break
        case 'set-field-prop':
          this.setFieldProp(data)
          break
      }
    },

    hideSome(id) {
      if (!this.hideList.includes(id)) {
        this.hideList.push(id)
      }
      console.log(this.hideList)
    },

    unhideSome(id) {
      const index = this.hideList.indexOf(id)
      if (index !== -1) {
        this.hideList.splice(index, 1)
      }
    },

    setFieldProp({ target, prop, value }) {
      this.map.some(a => {
        const f = (a || []).find(b => b.id === target)
        if (f) {
          f.option[prop] = value
          return true
        }
      })
    },

    getFields() {
      return this.$refs.field.filter(a => a.option && a.option.mold == 'field')
    },

    getFieldById(id) {
      return this.$refs.field.find(a => a.option && a.option.mold == 'field' && a.option.id == id)
    },

    check() {
      let check = true
      return this.getFields().reduce((a, child) => {
        return a.then(() => {
          if (check) {
            return Promise.resolve().then(() => child.check()).then(result => {
              check = result
            })
          }
        })
      }, Promise.resolve()).then(() => check)
    },

    getValue() {
      const r = {}
      return this.getFields().reduce((a, child) => {
        return a.then(() => {
          const name = child.option.name
          return Promise.resolve().then(() => child.getValue()).then(value => {
            r[name] = value
          })
        })
      }, Promise.resolve()).then(() => r)
    },

    setValue(data = {}) {
      return this.getFields().reduce((a, child) => {
        return a.then(() => {
          const name = child.state.name
          if (data.hasOwnProperty(name)) {
            return Promise.resolve().then(() => child.setValue(data[name]))
          }
        })
      }, Promise.resolve())
    }
  }
}
</script>
<style lang="scss" scoped>
.v-form-maker {
  .row {
    display: flex;
    .span {
      flex: 1;
      box-sizing: border-box;
      padding: 0 5px;
      &.hide {
        display: none;
      }
    }
  }
}
</style>
